﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using ShevaEngine.Core.Attributes;
using ShevaEngine.Core.Foundation;

namespace ShevaEngineTools.UserControls
{
    /// <summary>
    /// Property grid.
    /// </summary>
    public partial class ObjectSettings : UserControl
    {
        /// <summary>Selected object.</summary>
        private object _SelectedObject;

        /// <summary>Selected object.</summary>
        public object SelectedObject
        {
            get { return this._SelectedObject; }
            set
            {
                if (this._SelectedObject != value)
                {
                    this._SelectedObject = value;

                    this.FillTable();
                }
            }
        }

        /// <summary>
        /// Constructor.
        /// </summary>
        public ObjectSettings()
        {
            this.InitializeComponent();
            this.Dock = DockStyle.Fill;
        }

        /// <summary>
        /// Fill table.
        /// </summary>
        public void FillTable()
        {
            Type objectType = this._SelectedObject.GetType();

            this.LayoutPanel.Controls.Clear();
            this.LayoutPanel.RowStyles.Clear();
            this.LayoutPanel.RowCount = 1;         

            FieldInfo[] fieldInfos = objectType.GetFields();

            this.CreateFieldsItems(fieldInfos);

            PropertyInfo[] propertiesInfos = objectType.GetProperties();

            this.CreatePropertiesItems(propertiesInfos);
        }

        /// <summary>
        /// Method creates fields infos.
        /// </summary>
        /// <param name="fieldInfos"></param>
        private void CreateFieldsItems(FieldInfo[] infos)
        {
            foreach (FieldInfo fieldInfo in infos)
            {
                bool editable = false;
                SettingsControlType controlType = SettingsControlType.TextBox;
                BoundingAttribute bounding = new BoundingAttribute(0,0);

                foreach (object item in fieldInfo.GetCustomAttributes(true))
                {
                    if (item is EditableAttribute)
                        editable = (item as EditableAttribute).Value;
                    if (item is SettingsControlTypeAttribute)
                        controlType = (item as SettingsControlTypeAttribute).Value;
                    if (item is BoundingAttribute)
                        bounding = (item as BoundingAttribute);
                }

                if (editable)
                {
                    this.LayoutPanel.RowCount++;
                    this.LayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 25));

                    this.LayoutPanel.Controls.Add(this.CreateNameLabel(fieldInfo.Name));

                    switch (controlType)
                    {
                        case SettingsControlType.TextBox:
                            {
                                TextBox newLabelValue = new TextBox();

                                newLabelValue.Tag = fieldInfo;

                                if (fieldInfo.GetValue(this._SelectedObject) != null)
                                    newLabelValue.Text = fieldInfo.GetValue(this._SelectedObject).ToString();
                                else
                                    newLabelValue.Text = "";

                                newLabelValue.Dock = DockStyle.Fill;
                                newLabelValue.TextAlign = HorizontalAlignment.Left;

                                newLabelValue.TextChanged += new EventHandler(FieldInfoTextBoxChanged);

                                this.LayoutPanel.Controls.Add(newLabelValue);
                            }
                            break;
                        case SettingsControlType.NumericUpDown:
                            {
                                NumericUpDown newNumericUpDownValue = new NumericUpDown();

                                newNumericUpDownValue.Tag = fieldInfo;

                                if (fieldInfo.GetValue(this._SelectedObject) != null)
                                    newNumericUpDownValue.Value = (Decimal)Convert.ChangeType(
                                        fieldInfo.GetValue(this._SelectedObject), typeof(Decimal));                                

                                newNumericUpDownValue.Dock = DockStyle.Fill;
                                newNumericUpDownValue.TextAlign = HorizontalAlignment.Right;

                                newNumericUpDownValue.ValueChanged += new EventHandler(FieldInfoNumericUpDownValueChanged);

                                this.LayoutPanel.Controls.Add(newNumericUpDownValue);
                            }
                            break;
                        case SettingsControlType.TrackBar:
                            {
                                TrackBar newTrackbar = new TrackBar();

                                newTrackbar.Minimum = 0;
                                newTrackbar.Maximum = UInt16.MaxValue;

                                newTrackbar.Tag = new Pair<FieldInfo, BoundingAttribute>(fieldInfo, bounding);

                                newTrackbar.ValueChanged += new EventHandler(FieldTrackBarChanged);

                                Single floatValue = 0;

                                if (fieldInfo.GetValue(this._SelectedObject) != null)
                                    floatValue = (Single)Convert.ChangeType(fieldInfo.GetValue(this._SelectedObject), typeof(Single));

                                Single boundingMin = (Single)Convert.ChangeType(bounding.MinValue, typeof(Single));
                                Single boundingMax = (Single)Convert.ChangeType(bounding.MaxValue, typeof(Single));

                                newTrackbar.Value = (int)(floatValue * (UInt16.MaxValue / (boundingMax - boundingMin)));

                                newTrackbar.Dock = DockStyle.Fill;
                                this.LayoutPanel.Controls.Add(newTrackbar);
                            }
                            break;
                        case SettingsControlType.ColorPicker:
                            {
                                Button newButtonValue = new Button();

                                newButtonValue.Tag = fieldInfo;

                                Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.White;

                                if (fieldInfo.GetValue(this._SelectedObject) != null)
                                    color = (Microsoft.Xna.Framework.Color)fieldInfo.GetValue(this._SelectedObject);

                                newButtonValue.BackColor = Color.FromArgb(color.R, color.G, color.B);
                                newButtonValue.Dock = DockStyle.Fill;

                                newButtonValue.Click += new EventHandler(FieldColorPickerChanged);

                                this.LayoutPanel.Controls.Add(newButtonValue);
                            }
                            break;
                        case SettingsControlType.CheckBox:
                            {
                                CheckBox newCheckboxValue = new CheckBox();

                                newCheckboxValue.Tag = fieldInfo;

                                if (fieldInfo.GetValue(this._SelectedObject) != null)
                                    newCheckboxValue.Checked = (Boolean)fieldInfo.GetValue(this._SelectedObject);

                                newCheckboxValue.Dock = DockStyle.Fill;

                                newCheckboxValue.CheckedChanged += new EventHandler(FieldCheckBoxChanged);

                                this.LayoutPanel.Controls.Add(newCheckboxValue);
                            }
                            break;
                        default:
                            {
                                Label newLabelValue = new Label();

                                if (fieldInfo.GetValue(this._SelectedObject) != null)
                                    newLabelValue.Text = fieldInfo.GetValue(this._SelectedObject).ToString();
                                else
                                    newLabelValue.Text = "";

                                newLabelValue.Dock = DockStyle.Fill;
                                newLabelValue.TextAlign = ContentAlignment.MiddleLeft;
                                this.LayoutPanel.Controls.Add(newLabelValue);
                            }
                            break;
                    }
                }
            }
        }

        

        /// <summary>
        /// Field checkbox changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FieldCheckBoxChanged(object sender, EventArgs e)
        {
            ((sender as CheckBox).Tag as FieldInfo).SetValue(this._SelectedObject, (sender as CheckBox).Checked);
        }

        /// <summary>
        /// Color picker changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FieldColorPickerChanged(object sender, EventArgs e)
        {
            ColorDialog newColorDialog = new ColorDialog();

            newColorDialog.Color = (sender as Button).BackColor;

            if (newColorDialog.ShowDialog() == DialogResult.OK)
            {
                (sender as Button).BackColor = newColorDialog.Color;

                Microsoft.Xna.Framework.Color color = 
                    new Microsoft.Xna.Framework.Color(newColorDialog.Color.R, newColorDialog.Color.G, newColorDialog.Color.B);

                ((sender as Button).Tag as FieldInfo).SetValue(this._SelectedObject, color);
            }
        }

        /// <summary>
        /// Trackbar value changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FieldTrackBarChanged(object sender, EventArgs e)
        {
            BoundingAttribute bounding = ((sender as TrackBar).Tag as Pair<FieldInfo, BoundingAttribute>).Second;

            Single boundingMin = (Single)Convert.ChangeType(bounding.MinValue, typeof(Single));
            Single boundingMax = (Single)Convert.ChangeType(bounding.MaxValue, typeof(Single));

            ((sender as TrackBar).Tag as Pair<FieldInfo, BoundingAttribute>).First.SetValue(
                this._SelectedObject, (sender as TrackBar).Value / (UInt16.MaxValue / (boundingMax - boundingMin)));
        }

        
        /// <summary>
        /// Field info textbox changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void FieldInfoTextBoxChanged(object sender, EventArgs e)
        {
            ((sender as TextBox).Tag as FieldInfo).SetValue(this._SelectedObject, (sender as TextBox).Text);
        }

        /// <summary>
        /// Numeric Up Down value changed.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void FieldInfoNumericUpDownValueChanged(object sender, EventArgs e)
        {
            ((sender as NumericUpDown).Tag as FieldInfo).SetValue(this._SelectedObject,
                Convert.ChangeType((sender as NumericUpDown).Value, ((sender as NumericUpDown).Tag as FieldInfo).FieldType));
        }

        /// <summary>
        /// Method creates properties infos.
        /// </summary>
        /// <param name="fieldInfos"></param>
        private void CreatePropertiesItems(PropertyInfo[] infos)
        {
            foreach (PropertyInfo propertyInfo in infos)
            {
                bool editable = false;
                SettingsControlType controlType = SettingsControlType.TextBox;

                foreach (object item in propertyInfo.GetCustomAttributes(true))
                {
                    if (item is EditableAttribute)
                        editable = (item as EditableAttribute).Value;
                    if (item is SettingsControlTypeAttribute)
                        controlType = (item as SettingsControlTypeAttribute).Value;
                }

                if (editable)
                {
                    this.LayoutPanel.RowCount++;
                    this.LayoutPanel.RowStyles.Add(new RowStyle(SizeType.Absolute, 25));

                    this.LayoutPanel.Controls.Add(this.CreateNameLabel(propertyInfo.Name));

                    Label newLabelValue = new Label();

                    if (propertyInfo.GetValue(this._SelectedObject, null) != null)
                        newLabelValue.Text = propertyInfo.GetValue(this._SelectedObject, null).ToString();
                    else
                        newLabelValue.Text = "";

                    newLabelValue.Dock = DockStyle.Fill;
                    newLabelValue.TextAlign = ContentAlignment.MiddleLeft;
                    this.LayoutPanel.Controls.Add(newLabelValue);
                }
            }            
        }

        /// <summary>
        /// Method creates name label.
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        private Label CreateNameLabel(string name)
        {
            Label newLabel = new Label();            
            newLabel.Text = name;
            newLabel.Dock = DockStyle.Fill;
            newLabel.TextAlign = ContentAlignment.MiddleLeft;

            return newLabel;
        }
    }
}
